/*
 * Copyright (C) 2010-2011 Comcast Cable.  All Rights Reserved.
 */
package com.hercules.android.receiver.handlers.commands;

import com.hercules.android.receiver.AndroidReceiver;
import com.hercules.android.receiver.ApplicationData;
import com.hercules.android.receiver.LogUtil;
import com.hercules.android.receiver.handlers.commands.CommandHandlersUtil.ValidationException;
import com.hercules.android.receiver.model.commands.XRECommand;
import com.hercules.android.receiver.model.commands.XREConnectCommand;
import com.hercules.android.receiver.model.objects.XREApplication;
import com.hercules.android.receiver.model.objects.XREObject;
import com.hercules.android.receiver.model.objects.XREView;
import com.hercules.android.receiver.painting.XREObjectPainter;
import com.hercules.android.receiver.painting.XREObjectPainterException;
import com.hercules.android.receiver.painting.views.AndroidXREView;

import java.util.HashMap;
import java.util.Map;

/**
 * The handler used to process XREConnectCommand. It will populate the receiver's ApplicationData, according to the
 * information found in the command message. It will create the root XREView and root XREApplication. It extends
 * XRECommandHandler for convenience.
 * <p>
 * <b>Sample Usage:</b> Please look at sample usage of {@link XREAggregateCommandHandler}.
 * <p>
 * <b>Thread Safety:</b> This class is not thread safe since it has mutable fields. But if they are not changed after
 * first configured, then this class is used in a thread safe manner.
 *
 * @author liuliquan, 7realm
 * @author 7realm
 * @version 1.0
 */
public class XREConnectCommandHandler extends XRECommandHandler {
    /**
     * The painter used to perform technology specific initialization.
     * <p>
     * Initial value is null. Can be any value. If it is null then no initialization will be performed. It has getter
     * and setter.
     */
    private XREObjectPainter applicationPainter;

    /**
     * Default empty constructor.
     */
    public XREConnectCommandHandler() {
        // empty
    }

    /**
     * Handle given CONNECT command message.
     *
     * @param command the XRE CONNECT command to be handled
     * @param receiver the receiver for the XRE application
     * @throws IllegalArgumentException if given command or receiver is null
     * @throws InvalidXRECommandParameterException if session GUID parameter is not correct
     * @throws XRECommandHandlerException if any error occurs while handling the command
     */
    @SuppressWarnings("boxing")
    @Override
    protected void processCommandMessage(XRECommand command, AndroidReceiver receiver)
        throws XRECommandHandlerException {
        String methodName = "processCommandMessage";
        LogUtil.enter(getLogger(), this, methodName, command, receiver);

        try {
            // check arguments
            XREConnectCommand connectCommand = CommandHandlersUtil.checkCommand(command, XREConnectCommand.class);
            CommandHandlersUtil.checkNotNull(receiver, "receiver");

            // get application data
            ApplicationData applicationData = receiver.getApplicationData();
            if (applicationData == null) {
                throw new ValidationException("Value of 'receiver.applicationData' should not be null.");
            }
            
            if (applicationData.getParentReceiver() != null) {
            	receiver.setLocalBehaviorData(applicationData.getParentReceiver().getLocalBehaviorData());
            }
            
            Map<Integer, XREObject> elementsMap = applicationData.getElementsXREIdToObject();
            if (elementsMap == null) {
                elementsMap = new HashMap<Integer, XREObject>();
                applicationData.setElementsXREIdToObject(elementsMap);
            }
            if (applicationData.getViewsXREIdToView() == null) {
                applicationData.setViewsXREIdToView(new HashMap<Integer, AndroidXREView>());
            }
            if (applicationData.getNestedXREApplicationViewsIdToReceiver() == null) {
                applicationData.setNestedXREApplicationViewsIdToReceiver(new HashMap<Integer, AndroidReceiver>());
            }

            // set session GUID of application data
            CommandHandlersUtil.checkStringParameter("sessionGUID", connectCommand.getSessionGUID());
            applicationData.setSessionGUID(connectCommand.getSessionGUID());

            // set key map URL and version of application data
            applicationData.setKeyMapURL(connectCommand.getKeyMapURL());
            applicationData.setVersion(connectCommand.getVersion());

            // create and set XREApplication representing the root application
            XREApplication rootXREApplication = (XREApplication) elementsMap.get(XREObject.ID_ROOT_APPLICATION);
            if (rootXREApplication == null) {
                rootXREApplication = new XREApplication();
                rootXREApplication.setId(XREObject.ID_ROOT_APPLICATION);
                rootXREApplication.setSessionGUID(connectCommand.getSessionGUID());
                elementsMap.put(rootXREApplication.getId(), rootXREApplication);
            }

            // create and set XREView representing the root view
            AndroidXREView rootView = (AndroidXREView) receiver.getRootView();
            XREView rootXREView = (XREView) elementsMap.get(XREObject.ID_ROOT_VIEW);
            /*if (rootXREView == null) {
                rootXREView = new XREView();
                rootXREView.setId(XREObject.ID_ROOT_VIEW);
                // AndroidAssembly1 do not set application for root view
                elementsMap.put(rootXREView.getId(), rootXREView);

                // attach root UI view
                rootView.attachView(rootXREView);
            }*/

            // put root view to applicationData.viewsXREIdToView map
            applicationData.getViewsXREIdToView().put(rootXREView.getId(), rootView);

            // paint root view
            if (applicationPainter != null) {
                applicationPainter.paintView(receiver, rootXREView, command);
            }
            LogUtil.exit(getLogger(), this, methodName);
        } catch (IllegalArgumentException e) {
            throw LogUtil.error(getLogger(), this, methodName, e);
        } catch (XRECommandHandlerException e) {
            throw LogUtil.error(getLogger(), this, methodName, e);
        } catch (ValidationException e) {
            throw LogUtil.error(getLogger(), this, methodName, new XRECommandHandlerException(e.getMessage(), e));
        } catch (XREObjectPainterException e) {
            throw LogUtil.error(getLogger(), this, methodName, new XRECommandHandlerException(
                "Error occurred while application painter was painting root XRE view.", e));
        }
    }

    /**
     * Gets the painter used to perform technology specific initialization.
     *
     * @return the painter used to perform technology specific initialization
     */
    public XREObjectPainter getApplicationPainter() {
        return applicationPainter;
    }

    /**
     * Sets the painter used to perform technology specific initialization.
     *
     * @param applicationPainter the painter used to perform technology specific initialization
     */
    public void setApplicationPainter(XREObjectPainter applicationPainter) {
        this.applicationPainter = applicationPainter;
    }
}